package com.opdar.athena.client.agent.server;

import com.opdar.athena.base.Constants;
import com.opdar.athena.base.MessageType;
import com.opdar.athena.base.RedisSessionManager;
import com.opdar.athena.client.agent.base.Configuration;
import com.opdar.athena.client.agent.base.TcpSessionManager;
import com.opdar.athena.entities.UserEntity;
import com.opdar.athena.tcp.TcpRecive;
import com.opdar.athena.client.agent.task.UserBindCheckTask;
import com.opdar.athena.utils.JSONUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import io.netty.util.concurrent.EventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by shiju on 2017/6/27.
 */
public class IoSession {
    private final ChannelHandlerContext ctx;
    private boolean isHttp;
    private boolean isAgent;
    private String token;
    private UserBindCheckTask task;
    private final static Logger logger = LoggerFactory.getLogger(IoSession.class);

    public IoSession(ChannelHandlerContext ctx) {
        this.ctx = ctx;
        //开始检查用户绑定，60秒计数一次，计数达到2则认为是闲置连接，断开操作.
        task = UserBindCheckTask.start(ctx);
    }

    public EventExecutor executor() {
        return ctx.executor();
    }

    public boolean isAgent() {
        return isAgent;
    }

    public void setAgent(boolean agent,String token) {
        isAgent = agent;
        this.token = token;
    }

    public boolean downline() {
        Configuration.getConfiguration().removeSession(ctx);
        ctx.close();
        if(token != null){
            TcpSessionManager tcpSessionManager = Configuration.getConfiguration().getContext().getBean(TcpSessionManager.class);
            tcpSessionManager.remove(token);
        }
        return true;
    }

    public boolean isHttp() {
        return isHttp;
    }

    public void setHttp(boolean http) {
        isHttp = http;
    }

    public String getToken() {
        return token;
    }

    public void clearHeartbeat() {
        if(token != null){
            TcpSessionManager tcpSessionManager = Configuration.getConfiguration().getContext().getBean(TcpSessionManager.class);
            RedisSessionManager redisSessionManager = Configuration.getConfiguration().getContext().getBean(RedisSessionManager.class);
            tcpSessionManager.clearTimeout(token);
            redisSessionManager.clearTimeout(token);
        }
    }

    public void setToken(String token) {
        this.token = token;
        if (task != null) {
            task.stop();
            task = null;
        }
        RedisSessionManager redisSessionManager = Configuration.getConfiguration().getContext().getBean(RedisSessionManager.class);
        UserEntity user = redisSessionManager.get(token);
        if(user == null){
            downline();
        }else{
            if(Configuration.getConfiguration().getLocalAddress() != null){
                user.setStat(new UserEntity.Stat(Configuration.getConfiguration().getLocalAddress().getAddress().getHostAddress(),Configuration.getConfiguration().getLocalAddress().getPort()));
            }
            redisSessionManager.set(token,user, Constants.SESSION_TIMEOUT);
        }
    }

    public ChannelFuture write(int type,Object writeResult) {
        return write(type,writeResult,null);
    }

    public ChannelFuture write(int type, Object writeResult, String crossDomain) {
        Object result = null;
        if (isHttp) {
            byte[] bytes = JSONUtil.toJSONAsBytes(new TcpRecive(type,writeResult));
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                    HttpResponseStatus.OK,Unpooled.wrappedBuffer(bytes));
            if(crossDomain != null){
                response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, crossDomain);
            }
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH,
                    response.content().readableBytes());
            result = response;
        } else {
            result = new TcpRecive(type,writeResult);
        }
        return ctx.writeAndFlush(result);
    }

    public void heartbeat() {
        long time = System.currentTimeMillis();
        if(isAgent){
            TcpSessionManager tcpSessionManager = Configuration.getConfiguration().getContext().getBean(TcpSessionManager.class);
            time = tcpSessionManager.size();
            logger.debug("通道[{}]空闲",token);
        }else{
            logger.debug("[{}]正在心跳",token);
        }
        byte[] writeBuffer = new byte[8];
        writeBuffer[0] = (byte)(time >>> 56);
        writeBuffer[1] = (byte)(time >>> 48);
        writeBuffer[2] = (byte)(time >>> 40);
        writeBuffer[3] = (byte)(time >>> 32);
        writeBuffer[4] = (byte)(time >>> 24);
        writeBuffer[5] = (byte)(time >>> 16);
        writeBuffer[6] = (byte)(time >>>  8);
        writeBuffer[7] = (byte)(time);
        write(MessageType.HEARTBEAT,writeBuffer);
    }
}
